// $Id: char_traits.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2008-2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_CHAR_TRAITS_HPP
#define XPCOM_CHAR_TRAITS_HPP

#include <xpcom/config.hpp>
#include <cstddef>
#ifdef XPCOM_USE_STD_CHAR_TRAITS
#include <string>
#else // XPCOM_USE_STD_CHAR_TRAITS
#include <cstring>
#  ifdef XPCOM_HAS_2BYTE_WCHAR_T
#include <cwchar>
#  endif // XPCOM_HAS_2BYTE_WCHAR_T
#include <xpcom/types.hpp>
#endif // XPCOM_USE_STD_CHAR_TRAITS

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

#ifdef XPCOM_USE_STD_CHAR_TRAITS
using std::char_traits; // use std::char_traits directly

#else // XPCOM_USE_STD_CHAR_TRAITS

//
// Define our own char_traits
// It is just a subset of std::char_traits
//
template <typename CharT>
class char_traits
{
public:
    typedef CharT char_type;

    static void assign(char_type& c1, const char_type& c2)
    {
        c1 = c2;
    }

    static bool eq(const char_type& c1, const char_type& c2)
    {
        return c1 == c2;
    }

    static bool lt(const char_type& c1, const char_type& c2)
    {
        return c1 < c2;
    }

    static int compare(const char_type* s1, const char_type* s2, std::size_t n);
    static std::size_t length(const char_type* s);
    static char_type* copy(char_type* s1, const char_type* s2, std::size_t n);
    static char_type* move(char_type* s1, const char_type* s2, std::size_t n);
    static char_type* assign(char_type* s, std::size_t n, char_type a);

    static const char_type* find(
            const char_type* s, std::size_t n, const char_type& a);
};

//
// Specialization of char
//
template <>
class XPCOM_DECL char_traits<char>
{
public:
    typedef char char_type;

    static void assign(char_type& c1, const char_type& c2)
    {
        c1 = c2;
    }

    static bool eq(const char_type& c1, const char_type& c2)
    {
        return c1 == c2;
    }

    static bool lt(const char_type& c1, const char_type& c2)
    {
        return c1 < c2;
    }

    static int compare(const char_type* s1, const char_type* s2, std::size_t n)
    {
        return std::memcmp(s1, s2, n);
    }

    static std::size_t length(const char_type* s)
    {
        return std::strlen(s);
    }

    static char_type* copy(char_type* s1, const char_type* s2, std::size_t n)
    {
        return static_cast<char_type*>(std::memcpy(s1, s2, n));
    }

    static char_type* move(char_type* s1, const char_type* s2, std::size_t n)
    {
        return static_cast<char_type*>(std::memmove(s1, s2, n));
    }

    static char_type* assign(char_type* s, std::size_t n, char_type a)
    {
        return static_cast<char_type*>(std::memset(s, a, n));
    }

    static const char_type* find(
            const char_type* s, std::size_t n, const char_type& a)
    {
        return static_cast<const char_type*>(std::memchr(s, a, n));
    }
};

#ifdef XPCOM_HAS_2BYTE_WCHAR_T
//
// Specialization of wchar
// (wchar is the same type as wchar_t, see xpcom/types.hpp)
//
template <>
class XPCOM_DECL char_traits<wchar>
{
public:
    typedef wchar char_type;

    static void assign(char_type& c1, const char_type& c2)
    {
        c1 = c2;
    }

    static bool eq(const char_type& c1, const char_type& c2)
    {
        return c1 == c2;
    }

    static bool lt(const char_type& c1, const char_type& c2)
    {
        return c1 < c2;
    }

    static int compare(const char_type* s1, const char_type* s2, std::size_t n)
    {
        return std::wmemcmp(s1, s2, n);
    }

    static std::size_t length(const char_type* s)
    {
        return std::wcslen(s);
    }

    static char_type* copy(char_type* s1, const char_type* s2, std::size_t n)
    {
        return static_cast<char_type*>(std::wmemcpy(s1, s2, n));
    }

    static char_type* move(char_type* s1, const char_type* s2, std::size_t n)
    {
        return static_cast<char_type*>(std::wmemmove(s1, s2, n));
    }

    static char_type* assign(char_type* s, std::size_t n, char_type a)
    {
        return static_cast<char_type*>(std::wmemset(s, a, n));
    }

    static const char_type* find(
            const char_type* s, std::size_t n, const char_type& a)
    {
        return static_cast<const char_type*>(std::wmemchr(s, a, n));
    }
};

#else // XPCOM_HAS_2BYTE_WCHAR_T

#ifdef XPCOM_HAS_EXTERN_TEMPLATE
XPCOM_EXTERN_TEMPLATE class XPCOM_TEMPLATE_DECL char_traits<wchar>;
#endif // XPCOM_HAS_EXTERN_TEMPLATE

#endif // XPCOM_HAS_2BYTE_WCHAR_T

#endif // XPCOM_USE_STD_CHAR_TRAITS

} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_CHAR_TRAITS_HPP
